package controller.handstates;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

import javax.swing.Timer;

import commands.Command;
import commands.FoldCommand;
import controller.CommandManager;

import utilities.Utilities;

import model.CommandQueue;
import model.HandChain;
import model.Player;
import model.GameChain;
import model.Table;
import model.timers.BlindCounter;
import model.timers.HandTimer;

public abstract class AbstractState {

	protected HandChain handChain;
	protected Table table;
	protected CommandQueue queue;	
	protected HandTimer handTimer;
	protected BlindCounter blinds;
	
	public AbstractState(HandChain handChain, Table table, BlindCounter blinds){
		this.handChain = handChain;
		this.table = table;
		this.handTimer = null;
		this.blinds = blinds;
		initializeSeats();
	}
	
	
	public abstract void playState();
	public abstract AbstractState getNextState();
	
	public int getBigBlind(){
		return blinds.getBigBlind();
	}
	
	protected void initializeSeats(){
		// Hand has not started yet, so seat last action player to -1 (this indicates no new circle commands)
		handChain.setLastActionPlayerSeat(-1);
		
		// Set the active player to the person after the dealer		
		int dealerSeat = handChain.getDealerPlayer().getSeat();
		handChain.setActivePlayerSeat(dealerSeat);
//		handChain.getNextPlayer();
	}
	
	protected boolean roundOver() {
		boolean roundOver = false;
		// round is over once we have gone full circle or one player is left.
		if(handChain.getActivePlayerSeat() == handChain.getLastActionPlayerSeat() ){
			roundOver = true;
			System.out.println("Round is over due to full circle");
		}
		
		if(isHandOver()){
			roundOver = true;
			System.out.println("Round is over due to hand being over");
		}
		
		return roundOver;
	}
	
	public void setQueue(CommandQueue queue){
		this.queue = queue;
	}
	
	
		
	protected void playRound(){		
		while(!roundOver()){
			printHandState();
			if(handChain.getDealerPlayer().getChips() == 0){
				//player already has all their chips in the middle, they can not perform action, therefore skip them
				System.out.println("Player" + handChain.getActivePlayerSeat() + " is already all in");
				handChain.getNextPlayer();
				
			}else {
				//prompt player to perform action
				System.out.println("Prompting player" + handChain.getActivePlayerSeat() + " to perform an action.");
							
				//wait for action or timeoutevent 
				// Start turn timer
				this.handTimer = new HandTimer(1, handChain.getActivePlayer());
				handTimer.start();
				
				//wait
				Command c = null;
				while(c == null){
					c = queue.pop();
					// add a sleep here? polling is bad :(
					// would be nice to have some event type system such that there is no polling.
					// oh well.
				}				
				
				//when notified stop turn timer, perform users action
				handTimer.stop();
				if(!c.execute(this)){
					FoldCommand cFold = new FoldCommand(c.getPlayerSeat());
					cFold.execute(this);
				}
			}			
		}
		//take everyones cards
		for(Player p : table.getPlayers()){
			p.takeHand();
		}
	}
	
	
	public void printHandState(){
		System.out.print("*HandState");
		for(Player p : handChain.getPlayers()){
			System.out.print("\n\tPlayer" + p.getSeat() + " " + p.getChips() + " " + p.getChipsOnTable());
			if(p.getSeat() == handChain.getActivePlayerSeat()){
				System.out.print(" A");
			}	
			if(p.getSeat() == handChain.getLastActionPlayerSeat()){
				System.out.print(" L");
			}
		}
		System.out.print("\n");
	}
	
	public HandChain getHandChain(){
		return handChain;
	}
	
	public int callAmount(int seat){
		int alreadyPutIn = handChain.getPlayer(seat).getChipsOnTable();
		int biggestBetOnTable = this.largestBet();
		int callAmount = biggestBetOnTable - alreadyPutIn;
		return callAmount;
	}
	
	private int largestBet(){
		int largestBet = 0;
		for(Player p : handChain.getPlayers()){
			if(p.getChipsOnTable() > largestBet){
				largestBet = p.getChipsOnTable();
			}
		}
		return largestBet;
	}
	
	/**
	 * Checks if the hand is over. Hand Over Scenarios:
	 * 	A single player is left
	 *  A single player left and the other player do not have anymore chips 
	 *  No players left have any chips
	 * @return
	 */
	public boolean isHandOver(){
		int numberOfPlayers = handChain.size();
		int numberOfPlayersWithoutChips = 0;
		boolean over = false;
		
		
		for(Player p : handChain.getPlayers()){
			if(p.getChips() <= 0){
				numberOfPlayersWithoutChips++;
				if(p.getChips() < 0){
					System.out.println("ERROR: AbstractState.isHandOver : player" + p.getSeat() + "has negative chips.");
				}
			}
		}
		
		// round is over if there is only a single person left
		if(numberOfPlayers == 1){
			over = true;
		}
		// round is over if no players have chips, or if only a single player has chips
		if( numberOfPlayersWithoutChips == numberOfPlayers || numberOfPlayersWithoutChips + 1 == numberOfPlayers ){
			over = true;
		}
		
		return over;
	}	
}
